/*
    rpc路由服务端模块（业务层）：基础rpc服务端功能的实现
        1、rpc路由器（RpcRouter）：根据请求的服务名（方法名），路由到指定的服务
            1.1、提供一个rpc请求回调，被注册到dispatcher调度器，当收到rpc请求的时候调用。此回调能够根据服务名（方法名）进行路由，并调用对应的服务
            1.2、提供一个注册服务的接口，用来注册提供的服务
            1.3、要维护并管理所有的服务。此功能进行抽离封装，由服务管理器（ServiceManager）来完成
        2、服务管理器（ServiceManager）：维护并管理所有的服务
            2.1、对服务进行保存。为了方便对服务进行保存，对服务进行抽象描述（ServiceDescribe）
            2.2、提供插入服务、删除服务、获取服务接口
        3、服务描述类（ServiceDescribe）：服务的抽象描述
            3.1、服务应该具有服务名、执行函数、参数、返回值
            3.2、提供检查rpc请求中服务参数是否正确的接口，以及返回值合法性监测的接口
        4、服务描述构建者类（ServiceDescribeBuilder）
            4.1、构建服务描述对象（保留了工厂的功能，同时保证了服务描述类的可读性不被破坏）
*/
#pragma once
#include "../common/message.hpp"

namespace ns_jsonrpc
{
    namespace ns_server
    {
        // 服务的参数类型
        enum class ParamType
        {
            BOOL = 0,
            INTEGRAL,
            NUMERIC,
            STRING,
            ARRAY,
            OBJECT,
        };

        // 服务描述类
        class ServiceDescribe
        {
        public:
            using ServiceDescribePtr = std::shared_ptr<ServiceDescribe>;
            using ParamsDescribe = std::pair<std::string, ParamType>; // <参数名，参数类型>
            using ServerCallBack = std::function<void(const Json::Value &, Json::Value &)>;

        public:
            ServiceDescribe(std::string &methodName, std::vector<ParamsDescribe> &paramsDescribe, ServerCallBack &callback, ParamType returnType)
                : _method_name(std::move(methodName)), _params_describe(std::move(paramsDescribe)), _callback(std::move(callback)), _return_type(returnType)
            {
            }

            // 检查请求服务所携带的参数是否完整且合法
            bool paramsCheck(const Json::Value &params)
            {
                // 对参数进行检查，是否包含服务需要的所有参数已经对应类型是否正确
                for (auto &pd : _params_describe)
                {
                    // 参数完整性判断
                    if (!params.isMember(pd.first))
                    {
                        LOG_ERROR("rpcRequest parameters is error, %s paramete is missing\n", pd.first.c_str());
                        return false;
                    }
                    // 参数类型判断
                    if (!isEqualParamsType(pd.second, params[pd.first]))
                    {
                        LOG_ERROR("rpcRequest parameters type is error, %s paramete type is error\n", pd.first.c_str());
                        return false;
                    }
                }
                return true;
            }

            bool resultTypeCheck(const Json::Value &result)
            {
                bool ret = isEqualParamsType(_return_type, result);
                if (ret == false)
                    LOG_ERROR("result type is error, %d\n", _return_type);
                return ret;
            }

            Json::Value call(const Json::Value &params)
            {
                Json::Value result;
                _callback(params, result);
                return result;
            }

            // 返回方法名
            const std::string &methodName()
            {
                return _method_name;
            }

        private:
            // 参数类型对比
            bool isEqualParamsType(ParamType ptype, const Json::Value &val)
            {
                switch (ptype)
                {
                case ParamType::BOOL:
                    return val.isBool();
                case ParamType::INTEGRAL:
                    return val.isIntegral();
                case ParamType::NUMERIC:
                    return val.isNumeric();
                case ParamType::STRING:
                    return val.isString();
                case ParamType::ARRAY:
                    return val.isArray();
                case ParamType::OBJECT:
                    return val.isObject();
                }
                return false;
            }

        private:
            std::string _method_name;                     // 方法名
            std::vector<ParamsDescribe> _params_describe; // 参数描述
            ServerCallBack _callback;                     // 服务回调
            ParamType _return_type;                       // 返回值类型
        };

        // 建造者类（保留工厂的作用，同时保证了ServiceDescribe类的可读性不被破坏）
        class ServiceDescribeBuilder
        {
        public:
            void setMethodName(const std::string &methodName)
            {
                _method_name = methodName;
            }

            void setParamsDes(const std::string &name, ParamType type)
            {
                _params_describe.push_back({name, type});
            }

            void setCallback(const ServiceDescribe::ServerCallBack &callback)
            {
                _callback = callback;
            }

            void setReturnType(ParamType type)
            {
                _return_type = type;
            }

            // 构建服务描述对象
            ServiceDescribe::ServiceDescribePtr build()
            {
                return std::make_shared<ServiceDescribe>(_method_name, _params_describe, _callback, _return_type);
            }

        private:
            std::string _method_name;                                      // 方法名
            std::vector<ServiceDescribe::ParamsDescribe> _params_describe; // 参数描述
            ServiceDescribe::ServerCallBack _callback;                     // 服务回调
            ParamType _return_type;                                        // 返回值类型
        };

        // 服务管理类
        class ServiceManager
        {
        public:
            using ServiceManagerPtr = std::shared_ptr<ServiceManager>;

        public:
            // 插入一个服务
            void insert(const ServiceDescribe::ServiceDescribePtr &serviceDescribe)
            {
                std::unique_lock<std::mutex> lock(_mutex);  
                LOG_DEBUG("insert method describe, method name: %s\n", serviceDescribe->methodName().c_str());
                _servicesMap[serviceDescribe->methodName()] = serviceDescribe;
            }

            // 删除一个服务
            void remove(const std::string &methodName)
            {
                std::unique_lock<std::mutex> lock(_mutex);
                LOG_DEBUG("remove method describe, method name: %s\n", methodName.c_str());
                _servicesMap.erase(methodName);
            }

            // 查询一个服务
            ServiceDescribe::ServiceDescribePtr select(const std::string &methodName)
            {
                std::unique_lock<std::mutex> lock(_mutex);
                auto it = _servicesMap.find(methodName);
                if (it != _servicesMap.end())
                {
                    LOG_DEBUG("select method describe success, method name: %s\n", methodName.c_str());
                    return it->second;
                }
                LOG_DEBUG("select method describe error, method name: %s\n", methodName.c_str());
                return ServiceDescribe::ServiceDescribePtr();
            }

        private:
            std::map<std::string, ServiceDescribe::ServiceDescribePtr> _servicesMap; // <服务方法名，服务描述>
            std::mutex _mutex;
        };

        // rpc路由
        class RpcRouter
        {
        public:
            using RpcRouterPtr = std::shared_ptr<RpcRouter>;

        public:
            RpcRouter() : _service_manager(std::make_shared<ServiceManager>())
            {
            }

            // 请求回调（被设置给dispatcher调度器，当接收到rpc请求时调用）
            void onRpcRequest(const BaseConnection::BaseConnectionPtr &conn, RpcRequest::RpcRequestPtr &msg)
            {
                // boyd检查
                if (!msg->check())
                {
                    LOG_ERROR("rpc request failed, invalid message\n");
                    return;
                }
                // 1.查找rpc路由是否提供请求的服务
                ServiceDescribe::ServiceDescribePtr sd = _service_manager->select(msg->method());
                if (sd.get() == nullptr)
                {
                    LOG_ERROR("service not found, service name: %s\n", msg->method().c_str());
                    response(conn, msg, Json::Value(), RCode::RCODE_NOT_FOUND_SERVICE);
                    return;
                }
                // 2.服务的参数检查
                if (!sd->paramsCheck(msg->params()))
                {
                    LOG_ERROR("rpc request params is error, service name: %s\n", msg->method().c_str());
                    response(conn, msg, Json::Value(), RCode::RCODE_INVALID_PARAMS);
                    return;
                }
                // 3.服务调用 & 返回值类型检查
                Json::Value result = sd->call(msg->params());
                if (!sd->resultTypeCheck(result))
                {
                    LOG_ERROR("rpc service caller is error, service name: %s\n", msg->method().c_str());
                    response(conn, msg, result, RCode::RCODE_INTERNAL_ERROR);
                    return;
                }
                LOG_DEBUG("rpc service caller is ok, service name: %s\n", msg->method().c_str());
                // 4.返回结果
                response(conn, msg, result, RCode::RCODE_OK);
            }

            // 注册服务
            void registerMethod(const ServiceDescribe::ServiceDescribePtr &serviceDescribe)
            {
                _service_manager->insert(serviceDescribe);
            }

        private:
            void response(const BaseConnection::BaseConnectionPtr &conn, const RpcRequest::RpcRequestPtr &msg, const Json::Value &result, RCode rcode)
            {
                RpcResponse::RpcResponsePtr rsp = MessageFactory::create<RpcResponse>(); // 创建响应
                rsp->setId(msg->id());                                                   // 设置响应id（与请求id一一对应）
                rsp->setMType(MType::RSP_RPC);                                           // 响应类型
                rsp->setRCode(rcode);                                                    // 设置响应状态码
                rsp->setResult(result);                                                  // 设置响应结果
                conn->send(rsp);                                                         // 发送响应
            }

        private:
            ServiceManager::ServiceManagerPtr _service_manager;
        };
    }
}